<?php
// +----------------------------------------------------------------------
// | QSCMS
// +----------------------------------------------------------------------
// | Copyright (c)  2025 https://www.qqss.net All rights reserved.
// +----------------------------------------------------------------------
// | Licensed QSCMS is not free software, commercial use must purchase official license from official website to avoid unnecessary legal disputes.
// +----------------------------------------------------------------------
// | Author: Contract 990504246@qq.com
// +----------------------------------------------------------------------

namespace app\common\util;

/**
 * 仿B站BV号风格短ID编码器 实验性内容
 * @author qiyue
 * date 2025-06-05
 * 
 * // 示例
 * $encoder = new ShortIdEncoder();
 *
 * // 编码
 * $originalId = 123456789;
 * $encodedId  = $encoder->encode($originalId);
 * echo "Encoded ID: $encodedId\n";
 *
 * // 解码
 * $decodedId = $encoder->decode($encodedId);
 * echo "Decoded ID: $decodedId\n";
 */

class ShortIdEncoder
{
    // 58位自定义字符表
    private $charset = 'fZodR9XQDSUm21yCkr6zBqiveYah8bt4xsWpHnJE7jL5VG3guMTKNPAwcF';
    private $length = 10; // 固定长度
    private $salt = 0x5A5A5A5A; // 可自定义盐值

    /**
     * 编码：将数字ID转换为10位短ID
     * @param int $id
     * @return string
     */
    public function encode($id)
    {
        $id      = (int) $id;
        $num     = $id ^ $this->salt; // 异或混淆
        $encoded = '';
        for ($i = 0; $i < $this->length; $i++) {
            $encoded = $this->charset[$num % 58] . $encoded;
            $num     = intval($num / 58);
        }
        return $encoded;
    }

    /**
     * 解码：将短ID还原为数字ID
     * @param string $shortId
     * @return int
     */
    public function decode($shortId)
    {
        $num = 0;
        for ($i = 0; $i < strlen($shortId); $i++) {
            $pos = strpos($this->charset, $shortId[$i]);
            if ($pos === false) {
                throw new \InvalidArgumentException('短ID包含非法字符');
            }
            $num = $num * 58 + $pos;
        }
        return $num ^ $this->salt;
    }
}
